using System;

namespace Arcane.Source.Combat
{
    public class Meta
    {
        public event Action<Val> OnValueChanged;

        private Val _val;
        public Val Value
        {
            get => _val;
            set
            {
                _val = value;
                OnValueChanged?.Invoke(_val);
            }
        }

        public Meta(Val value)
        {
            _val = value;
        }

        public enum Type
        {
            Void,
            Bool,
            Int,
            Float,
        }

        public struct Val
        {
            public const byte CONTENT_SIZE = sizeof(float);

            public Type ty;
            private unsafe fixed byte bytes[CONTENT_SIZE];

            private unsafe Val(byte[] managed)
            {
                fixed (byte* pSrc = managed, pDst = bytes)
                {
                    Buffer.MemoryCopy(pSrc, pDst, CONTENT_SIZE, managed.Length);
                }
            }

            public Val()
            {
                ty = Type.Void;
            }

            public Val(bool v)
            {
                unsafe
                {
                    bytes[0] = (byte)(v ? 1 : 0);
                }
                ty = Type.Bool;
            }

            public Val(int v) : this(BitConverter.GetBytes(v))
            {
                ty = Type.Int;
            }

            public Val(float v) : this(BitConverter.GetBytes(v))
            {
                ty = Type.Float;
            }

            public unsafe bool AsBool()
            {
                fixed (byte* p = bytes)
                {
                    return p[0] != 0;
                }
            }

            public unsafe int AsInt32()
            {
                fixed (byte* p = bytes)
                {
                    return BitConverter.ToInt32(new ReadOnlySpan<byte>(p, CONTENT_SIZE));
                }
            }

            public unsafe float AsSingle()
            {
                fixed (byte* p = bytes)
                {
                    return BitConverter.ToSingle(new ReadOnlySpan<byte>(p, CONTENT_SIZE));
                }
            }

            public bool TryAsBool(out bool v)
            {
                if (ty == Type.Bool)
                {
                    v = AsBool();
                    return true;
                }
                v = default;
                return false;
            }

            public bool TryAsInt32(out int v)
            {
                if (ty == Type.Int)
                {
                    v = AsInt32();
                    return true;
                }
                v = default;
                return false;
            }

            public bool TryAsSingle(out float v)
            {
                if (ty == Type.Float)
                {
                    v = AsSingle();
                    return true;
                }
                v = default;
                return false;
            }
        }
    }
}